package com.ygl.core.listener.loadbalance;

import com.netflix.loadbalancer.Server;
import com.ygl.common.entity.DiscoveryEntity;
import com.ygl.common.entity.RegionEntity;
import com.ygl.common.entity.RegionFilterEntity;
import com.ygl.common.entity.RuleEntity;
import com.ygl.core.listener.BasicListener;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @Author yanggld
 * @Date 2019/12/17-15:41
 * @Description 负载均衡-区域匹配拦截器
 */
@Slf4j
public class RegionFilterLoadBalanceListener extends BasicListener implements LoadBalanceListener {


	@Override
	public void onGetServers(String serviceId, List<? extends Server> servers) {
		String consumerServiceId = coreAdapter.getServiceId();
		String consumerServiceRegion = coreAdapter.getRegion();
		applyRegionFilter(consumerServiceId,consumerServiceRegion,serviceId,servers);
		if (servers != null) {
			log.info(consumerServiceId+":"+consumerServiceRegion+"------>>>>>>"+serviceId+"---------区域匹配结果："+servers.size());
		}
	}

	private void applyRegionFilter(String consumerServiceId, String consumerServiceRegion, String providerServiceId, List<? extends Server> servers) {
		// 如果消费端未配置区域号，那么它可以调用提供端所有服务，需要符合规范，极力避免该情况发生
		if (StringUtils.isEmpty(consumerServiceRegion)) {
			return;
		}

		RuleEntity ruleEntity = coreAdapter.getRule();
		if (ruleEntity == null) {
			return;
		}
		DiscoveryEntity discoveryEntity = ruleEntity.getDiscoveryEntity();
		if (discoveryEntity == null) {
			return;
		}
		RegionFilterEntity regionFilterEntity = discoveryEntity.getRegionFilterEntity();
		if (regionFilterEntity == null) {
			return;
		}
		Map<String, List<RegionEntity>> regionEntityMap = regionFilterEntity.getRegionEntityMap();
		if (MapUtils.isEmpty(regionEntityMap)) {
			return;
		}
		/**
		 * 获取服务消费者 可以 调用的服务提供者的版本
		 */
		List<RegionEntity> regionEntityList = regionEntityMap.get(consumerServiceId);
		if (CollectionUtils.isEmpty(regionEntityList)) {
			return;
		}

		// 当前区域的消费端所能调用提供端的区域号列表
		List<String> allNoFilterValueList = null;
		// 提供端规则未作任何定义
		boolean providerConditionDefined = false;
		for (RegionEntity regionEntity : regionEntityList) {
			String providerServiceName = regionEntity.getProviderServiceName();
			if (StringUtils.equalsIgnoreCase(providerServiceName, providerServiceId)) {
				providerConditionDefined = true;

				List<String> consumerRegionValueList = regionEntity.getConsumerRegionValueList();
				List<String> providerRegionValueList = regionEntity.getProviderRegionValueList();

				// 判断consumer-region-value值是否包含当前消费端的区域号
				// 如果consumerRegionValueList为空，表示消费端区域列表未指定，那么任意消费端区域可以访问指定区域提供端区域
				if (CollectionUtils.isNotEmpty(consumerRegionValueList)) {
					if (consumerRegionValueList.contains(consumerServiceRegion)) {
						if (allNoFilterValueList == null) {
							allNoFilterValueList = new ArrayList<String>();
						}
						if (CollectionUtils.isNotEmpty(providerRegionValueList)) {
							allNoFilterValueList.addAll(providerRegionValueList);
						}
					} // 这里的条件，在每一次循环都不满足，会让allNoFilterValueList为null，意味着定义的区域关系都不匹配
				} else {
					if (allNoFilterValueList == null) {
						allNoFilterValueList = new ArrayList<String>();
					}
					if (CollectionUtils.isNotEmpty(providerRegionValueList)) {
						allNoFilterValueList.addAll(providerRegionValueList);
					}
				}
			}
		}

		if (allNoFilterValueList != null) {
			// 当allNoFilterValueList为空列表，意味着区域对应关系未做任何定义（即所有的providerRegionValueList为空），不需要执行过滤，直接返回
			if (allNoFilterValueList.isEmpty()) {
				return;
			} else {
				Iterator<? extends Server> iterator = servers.iterator();
				while (iterator.hasNext()) {
					Server server = iterator.next();
					String serverRegion = coreAdapter.getServerRegion(server);
					if (!allNoFilterValueList.contains(serverRegion)) {
						iterator.remove();
					}
				}
			}
		} else {
			if (providerConditionDefined) {
				// 当allNoFilterValueList为null, 意味着定义的区域关系都不匹配，直接清空所有实例
				servers.clear();
			}
		}
	}

	@Override
	public int getOrder() {
		// After version filter
		return HIGHEST_PRECEDENCE + 2;
	}
}
